package com.test.example.controller.xss;

import cn.hutool.http.HtmlUtil;
import com.xingluo.tools.result.Result;
import com.xingluo.tools.xss.aspect.XSSProtect;
import com.xingluo.tools.xss.aspect.XssMode;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.http.HttpHeaders;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;


@RestController
@Tag(name="防XSS攻击测试")
@SecurityRequirement(name = "SaToken")
public class XssController {

    /**
     * 无XSS攻击预防
     */
    @GetMapping("/xss")
    public String xss() {
        return "<script>alert('abc')</script>";
    }

    /**
     * 自定义校验注解
     * @param user 使用@Xss添加至字段上
     */
    @Operation(summary = "查询全部学生数据", description = "查询学生信息，并返回响应结果信息")
    @Parameters({
        @Parameter(name="", description="", required=true, in = ParameterIn.PATH, schema=@Schema(implementation = Integer.class)),
        @Parameter(name="", description="", required=true, in = ParameterIn.QUERY, schema=@Schema(implementation = Integer.class)),
    })
    @PostMapping("/xss1")
    public String xss(@Valid User user) {
        return "@Xss校验，如果有XSS攻击，则全局异常处理器中返回错误信息";
    }

    /**
     * 输出编码
     */
    @PostMapping("/xss2")
    public String xss2() {
        // 若恶意脚本已经成功注入
        User user = new User("<script>alert('abc')</script>", "abc");
        // 可以通过方法对输出防XSS攻击处理
//        return HtmlUtil.escape(user.getUsername());   // 转义
        return HtmlUtil.unescape(HtmlUtil.filter(user.getUsername()));   // 清除，过滤HTML文本，防止XSS攻击
    }

    /**
     * 自定义序列化注解@Xss，序列化有两种模式：ESCAPE：转义(默认)，CLEAR：清理
     */
    @PostMapping("/xss3")
    public Result xss3() {
        // 若恶意脚本已经成功注入
        User user = new User("<script>alert('abc')</script>", "<script>alert('info')</script>");
        return Result.success(user);
    }

    // ---------------------------------前面注解可以不配置文件中配置开启直接使用------------------

    /**
     * 使用@XSSProtect注解，可以对所有参数进行处理，注意需要配置开启，默认清除模式CLEAR
     */
    @XSSProtect
    @PostMapping("/xss4")
    @SecurityRequirement(name = HttpHeaders.AUTHORIZATION)
    public Result xss4(User user) {
        System.out.println(user.getUsername());
        System.out.println(user.getInfo());
        return Result.success(user);
    }

    /*
     * 转义模式：ESCAPE，接收form-data格式
     * 使用了@XSSProtect转义模式ESCAPE（默认），返回数据对象中就不要再用@Xss注解了，不然@Xss(CLEAR)会反转义，@Xss(ESCAPE)返回序列化会再做一次转义，会两次转义了
     */
    @XSSProtect(XssMode.ESCAPE)
    @PostMapping("/xss5")
    public Result xss5(User user) {
        System.out.println(user.getUsername());
        System.out.println(user.getInfo());
        return Result.success(user);
    }

    /*
     * 校验模式：VALID，接收json格式
     */
    @XSSProtect(XssMode.VALID)
    @PostMapping("/xss6")
    public Result xss6(@RequestBody User user) {
        System.out.println(user.getUsername());
        System.out.println(user.getInfo());
        return Result.success(user);
    }

    /**
     * 使用过滤器，可以不使用任何注解了，接收form-data
     * 如果使用转义模式，同样最好就不要再用@Xss注解，否则会出现反转义和二次转义
     */
    @PostMapping("/xss7")
    public Result xss7(User user) {
        System.out.println(user.getUsername());
        System.out.println(user.getInfo());
        return Result.success(user);
    }

    /**
     * 使用过滤器，可以不使用任何注解了，接收json格式
     */
    @PostMapping("/xss8")
    public Result xss8(@RequestBody User user) {
        System.out.println(user.getUsername());
        System.out.println(user.getInfo());
        return Result.success(user);
    }
}
